{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "84a0565a",
   "metadata": {},
   "source": [
    "# \"智能\"点的选择提示词"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c5eb49bd",
   "metadata": {
    "vscode": {
     "languageId": "plaintext"
    }
   },
   "source": [
    "FewShotPromptTemplate 有个明显特性：不管用户输入的问题是什么，都会把所有示例一股脑地包含进去。但在实际开发时，完全可以根据当前的具体输入，用示例选择器从海量候选示例里精准挑出关联性最强的那部分示例。\n",
    "\n",
    "既能避免不加区分地传递所有示例，节省 token 消耗，又能让输出效果更优。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "59e078a0",
   "metadata": {},
   "source": [
    "语义相似选择：通过余弦相似度等指标衡量语义关联度，最终选出与输入问题最相似的 k 个示例。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "24e76e62",
   "metadata": {},
   "source": [
    "长度选择：按照输入文本的长度，从候选示例中筛选出长度最贴近的内容。这种方式不仅能强化模型对文本结构的理解，而且比计算语义相似度更简洁高效，很适合对响应速度要求高的场景。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "adcf2999",
   "metadata": {},
   "source": [
    "最大边际相关示例选择：先着重挑选与输入问题语义相近的示例，同时借助惩罚机制，防止返回的内容出现同质化问题。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d8d8701d",
   "metadata": {},
   "source": [
    "# 基础应用 LengthBasedExampleSelector"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "662054d8",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.example_selectors import LengthBasedExampleSelector\n",
    "from langchain_core.prompts.prompt import PromptTemplate\n",
    "# 2. 准备示例数据\n",
    "examples = [\n",
    "    {\"input\": \"你好\", \"output\": \"您好！请问有什么可以帮助您的？\"},\n",
    "    {\"input\": \"订单什么时候发货？\", \"output\": \"您的订单将在24小时内发出，物流信息会同步到您的账户。\"},\n",
    "    {\"input\": \"我想退货，因为收到的商品有破损\", \"output\": \"很抱歉给您带来不便。请您提供订单号和商品破损照片，我们会安排上门取件并为您办理退款。\"}\n",
    "]\n",
    "\n",
    "# 3. 创建示例模板（英文变量，定义示例格式）\n",
    "example_prompt = PromptTemplate(\n",
    "    input_variables=[\"input\", \"output\"],  # 英文变量名\n",
    "    template=\"用户问：{input}\\n回复：{output}\\n\"  # 模板内容用中文描述格式\n",
    ")\n",
    "\n",
    "# 4. 初始化长度-based示例选择器\n",
    "example_selector = LengthBasedExampleSelector(\n",
    "    examples=examples,\n",
    "    example_prompt=example_prompt,\n",
    "    max_length=20  # 最大长度设为100（默认按空格/换行分割计数）\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "55789450",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "输入1选择的示例：\n",
      "{'input': '你好', 'output': '您好！请问有什么可以帮助您的？'}\n",
      "{'input': '订单什么时候发货？', 'output': '您的订单将在24小时内发出，物流信息会同步到您的账户。'}\n",
      "{'input': '我想退货，因为收到的商品有破损', 'output': '很抱歉给您带来不便。请您提供订单号和商品破损照片，我们会安排上门取件并为您办理退款。'}\n"
     ]
    }
   ],
   "source": [
    "# 5. 使用同步方法选择示例\n",
    "# 测试用例1：输入较短\n",
    "input1 = {\"user_query\": \"在吗？\"}  # 英文键，中文内容\n",
    "selected1 = example_selector.select_examples(input1)\n",
    "print(\"输入1选择的示例：\")\n",
    "for eg in selected1:\n",
    "    print(eg)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "c7154be7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "输入2选择的示例：\n",
      "{'input': '你好', 'output': '您好！请问有什么可以帮助您的？'}\n",
      "{'input': '订单什么时候发货？', 'output': '您的订单将在24小时内发出，物流信息会同步到您的账户。'}\n",
      "{'input': '我想退货，因为收到的商品有破损', 'output': '很抱歉给您带来不便。请您提供订单号和商品破损照片，我们会安排上门取件并为您办理退款。'}\n"
     ]
    }
   ],
   "source": [
    "# 测试用例2：输入较长\n",
    "input2 = {\"user_query\": \"我上周买的手机屏幕有问题，经常闪屏，想换一个新的，需要什么手续？\"}\n",
    "selected2 = example_selector.select_examples(input2)\n",
    "print(\"\\n输入2选择的示例：\")\n",
    "for eg in selected2:\n",
    "    print(eg)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "90a7b512",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "输入1选择的示例：\n",
      "{'input': '你好', 'output': '您好！请问有什么可以帮助您的？'}\n",
      "{'input': '订单什么时候发货？', 'output': '您的订单将在24小时内发出，物流信息会同步到您的账户。'}\n",
      "{'input': '我想退货，因为收到的商品有破损', 'output': '很抱歉给您带来不便。请您提供订单号和商品破损照片，我们会安排上门取件并为您办理退款。'}\n",
      "\n",
      "输入2选择的示例：\n",
      "{'input': '你好', 'output': '您好！请问有什么可以帮助您的？'}\n",
      "{'input': '订单什么时候发货？', 'output': '您的订单将在24小时内发出，物流信息会同步到您的账户。'}\n",
      "{'input': '我想退货，因为收到的商品有破损', 'output': '很抱歉给您带来不便。请您提供订单号和商品破损照片，我们会安排上门取件并为您办理退款。'}\n",
      "\n",
      "添加新示例后选择的示例：\n",
      "{'input': '你好', 'output': '您好！请问有什么可以帮助您的？'}\n",
      "{'input': '订单什么时候发货？', 'output': '您的订单将在24小时内发出，物流信息会同步到您的账户。'}\n",
      "{'input': '我想退货，因为收到的商品有破损', 'output': '很抱歉给您带来不便。请您提供订单号和商品破损照片，我们会安排上门取件并为您办理退款。'}\n",
      "{'input': '多少钱？', 'output': '该商品当前售价99元，支持满100减10的活动哦~'}\n"
     ]
    }
   ],
   "source": [
    "\n",
    "\n",
    "# 6. 同步添加新示例（中文内容，英文键）\n",
    "new_example = {\n",
    "    \"input\": \"多少钱？\",\n",
    "    \"output\": \"该商品当前售价99元，支持满100减10的活动哦~\"\n",
    "}\n",
    "example_selector.add_example(new_example)  # 同步添加\n",
    "\n",
    "# 查看添加后的效果\n",
    "input3 = {\"user_query\": \"这个东西怎么用？\"}\n",
    "selected3 = example_selector.select_examples(input3)\n",
    "print(\"\\n添加新示例后选择的示例：\")\n",
    "for eg in selected3:\n",
    "    print(eg)\n",
    "# 输出（可能包含新添加的短示例，总长度不超过限制）：\n",
    "# {'input': '你好', 'output': '您好！请问有什么可以帮助您的？'}\n",
    "# {'input': '多少钱？', 'output': '该商品当前售价99元，支持满100减10的活动哦~'}\n",
    "# {'input': '订单什么时候发货？', 'output': '您的订单将在24小时内发出，物流信息会同步到您的账户。'}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fe7623bc",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_community.vectorstores import Chroma\n",
    "from langchain_core.example_selectors import SemanticSimilarityExampleSelector"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "langchain-course (3.10.12)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
